/*
 * @Author       : wfl
 * @LastEditors  : wfl
 * @description  :
 * @updateInfo   :
 * @Date         : 2023-10-11 15:42:03
 * @LastEditTime : 2024-01-30 10:46:39
 */
import { Get, Provide, Param, Post, Query, Body } from '@midwayjs/decorator';
import { Inject } from '@midwayjs/core';
import { CoolController, BaseController } from '@cool-midway/core';
import { ScreenEntity } from '../../entity/screen';
import { ScreenService } from '../../service/screen';
import { BaseSysDepartmentService } from '../../../base/service/sys/department';
import { ComponentService } from '../../../coms/service/component';
import { FilterService } from '../../../filter/service/filter';
import { ScreenReleaseService } from '../../../release/service/release';
// import { ZipService } from '../../service/zip';

import * as archiver from 'archiver';

import * as fs from 'fs';
import { join } from 'path';
import * as fse from 'fs-extra';

const JSON_PATH = '../../../../../nginx/server/source/';
const STATIC_PATH = '../../../../../nginx/public/uploads/';

/**
 * 项目-大屏
 */
@Provide()
@CoolController({
  api: ['add', 'delete', 'update', 'info', 'list', 'page'],
  entity: ScreenEntity,
  service: ScreenService,
  listQueryOp: {
    keyWordLikeFields: ['name'],
  },
  before: ctx => {
    if (
      ['/app/screen/screen/add', '/app/screen/screen/update'].includes(
        ctx.request.url
      )
    ) {
      const {
        pages,
        dialogs,
        variables,
        styleFilterParams,
        host,
        events,
        iframe,
      } = ctx.request.body;
      ctx.request.body = {
        ...ctx.request.body,
        pages: JSON.stringify(pages),
        dialogs: JSON.stringify(dialogs),
        variables: JSON.stringify(variables),
        host: JSON.stringify(host),
        events: JSON.stringify(events),
        iframe: JSON.stringify(iframe),
        styleFilterParams: JSON.stringify(styleFilterParams),
      };
    }
  },
  pageQueryOp: {
    keyWordLikeFields: ['name'],
    addOrderBy: {
      createTime: 'desc',
    },
  },
})
export class ScreensController extends BaseController {
  @Inject()
  baseSysDepartmentService: BaseSysDepartmentService;

  @Inject()
  componentService: ComponentService;

  @Inject()
  filterService: FilterService;

  @Inject()
  screenReleaseService: ScreenReleaseService;

  // @Inject()
  // zipService: ZipService;

  @Get('/:id')
  async queryScreenById(@Param('id') id: string) {
    const res = await (this.service as any).queryById(id);
    return this.ok(res);
  }

  @Post('/export/screen')
  async exportScreenById(@Body() body) {
    // 大屏配置
    const res = await (this.service as any).queryById(body.id);
    // 大屏下的组件
    const coms = await this.componentService.queryComsByProjectId(body.id);
    // 大屏下的过滤器
    const filters = await this.filterService.getFilterList({
      projectId: body.projectId,
      screenId: body.id,
    });
    // 将数据库数据转为json文件存储在子服务中
    const dir = `${JSON_PATH}${body.id}`;
    const comName = 'com.json';
    const configName = 'config.json';
    let filePath = join(__dirname, dir);
    fs.access(filePath, err => {
      if (err) {
        fs.mkdirSync(filePath, { recursive: true });
      }
      // 大屏配置
      fs.writeFile(
        `${filePath}/${configName}`,
        JSON.stringify(res, null, 2),
        err => {
          if (err) {
            console.error(err);
            return;
          }
          // 文件被成功写入
          console.log(`${configName} 已成功创建并写入内容.`);
        }
      );
      // 大屏组件
      fs.writeFile(
        `${filePath}/${comName}`,
        JSON.stringify(coms, null, 2),
        err => {
          if (err) {
            console.error(err);
            return;
          }
          // 文件被成功写入
          console.log(`${comName} 已成功创建并写入内容.`);
        }
      );
    });

    // 静态资源
    const staticDir = `../../../../../public/uploads/${body.projectId}`;
    const toStaticDir = `${STATIC_PATH}${body.projectId}`;
    try {
      await fse.copy(join(__dirname, staticDir), join(__dirname, toStaticDir));
    } catch (error) {}

    // 创建zip文件
    const fileSource = join(__dirname, '../../../../../nginx');
    const outputName = `${res.name}_${new Date().getTime()}.zip`;
    const outPut = fs.createWriteStream(outputName);
    const archive = archiver('zip', { zlib: { level: 9 } });

    // 设置输出到 HTTP 响应流
    archive.pipe(outPut);

    try {
      await archive.directory(`${fileSource}/`, false);
      // this.baseCtx.res.
      outPut.on('close', () => {
        // fs.unlinkSync(outputName);
        // 删除之前生成用于压缩的文件
      });
      archive.finalize();
    } catch (err) {
      console.error('Archiving error:', err);
      return;
    }

    // 监听归档完成事件和错误事件
    archive.on('finish', async () => {
      console.log(`Archive wrote ${archive.pointer()} total bytes.`);
      await fse.move(
        join(__dirname, `../../../../../${outputName}`),
        join(
          __dirname,
          `../../../../../public/release/${body.id}/${outputName}`
        )
      );
      console.log('文件已成功移动');
      await this.screenReleaseService.addRelease({
        screenId: body.id,
        name: outputName,
        fileUrl: `/public/release/${body.id}/${outputName}`,
      } as any);
      this.baseCtx.res.end();
    });

    archive.on('error', err => {
      console.error('Archiver error:', err);
    });

    return this.ok({
      message: '正在打包，请稍后查看下载...',
    });
  }

  @Post('/export/screens')
  async exportScreenByIds(@Body() body) {
    await fse.emptyDir(join(__dirname, STATIC_PATH));
    await fse.emptyDir(join(__dirname, JSON_PATH));
    let name = '';
    for await (const item of body.id) {
      // 大屏配置
      const res = await (this.service as any).queryById(item);
      name += `${res.name}_`;
      // 大屏下的组件
      const coms = await this.componentService.queryComsByProjectId(item);
      // 大屏下的过滤器
      const filters = await this.filterService.getFilterList({
        projectId: body.projectId,
        screenId: item,
      });
      // 将数据库数据转为json文件存储在子服务中
      const dir = `${JSON_PATH}${item}`;
      const comName = 'com.json';
      const configName = 'config.json';
      let filePath = join(__dirname, dir);
      fs.access(filePath, err => {
        if (err) {
          fs.mkdirSync(filePath, { recursive: true });
        }
        // 大屏配置
        fs.writeFile(
          `${filePath}/${configName}`,
          JSON.stringify(res, null, 2),
          err => {
            if (err) {
              console.error(err);
              return;
            }
            // 文件被成功写入
            console.log(`${configName} 已成功创建并写入内容.`);
          }
        );
        // 大屏组件
        fs.writeFile(
          `${filePath}/${comName}`,
          JSON.stringify(coms, null, 2),
          err => {
            if (err) {
              console.error(err);
              return;
            }
            // 文件被成功写入
            console.log(`${comName} 已成功创建并写入内容.`);
          }
        );
      });
    }

    // 静态资源
    const staticDir = `../../../../../public/uploads/${body.projectId}`;
    const toStaticDir = `${STATIC_PATH}${body.projectId}`;
    try {
      await fse.copy(join(__dirname, staticDir), join(__dirname, toStaticDir));
    } catch (error) {}

    // 创建zip文件
    const fileSource = join(__dirname, '../../../../../nginx');
    const outputName = `${name}_${new Date().getTime()}.zip`;
    const outPut = fs.createWriteStream(outputName);
    const archive = archiver('zip', { zlib: { level: 9 } });

    // 设置输出到 HTTP 响应流
    archive.pipe(outPut);

    try {
      await archive.directory(`${fileSource}/`, false);
      // this.baseCtx.res.
      outPut.on('close', () => {
        // fs.unlinkSync(outputName);
        // 删除之前生成用于压缩的文件
      });
      archive.finalize();
    } catch (err) {
      console.error('Archiving error:', err);
      return;
    }

    // 监听归档完成事件和错误事件
    archive.on('finish', async () => {
      console.log(`Archive wrote ${archive.pointer()} total bytes.`);
      await fse.move(
        join(__dirname, `../../../../../${outputName}`),
        join(
          __dirname,
          `../../../../../public/release/${body.id}/${outputName}`
        )
      );
      console.log('文件已成功移动');
      await this.screenReleaseService.addRelease({
        projectId: body.projectId,
        screenId: body.id?.join(','),
        name: outputName,
        fileUrl: `/public/release/${body.id}/${outputName}`,
      } as any);
      this.baseCtx.res.end();
    });

    archive.on('error', err => {
      console.error('Archiver error:', err);
    });

    return this.ok({
      message: '正在打包，请稍后查看下载...',
    });
  }
  /**
   * @description: 根据projectId查询所有大屏
   * @return {*}
   */
  @Get('/apps')
  async queryScreenInProject(@Query() param: any) {
    const res = await (this.service as any).getScreenWithChildren(param);
    return this.ok(res);
  }

  @Post('/copy')
  async copyScreen(@Body('id') id: string) {
    const res = await (this.service as any).copyScreen(id);
    return this.ok(res);
  }

  @Post('/rename')
  async renameScreen(@Body() obj: { id: string; name: string }) {
    const res = await (this.service as any).renameScreen(obj.id, obj.name);
    return this.ok(res);
  }

  @Post('/publish/info')
  async publishInfo(@Body('id') id: string) {
    const res = await (this.service as any).publishInfo(id);
    return this.ok(res);
  }

  @Post('/publish')
  async publishScreen(@Body() screen: Object) {
    const res = await (this.service as any).publishScreen(screen);
    return this.ok(res);
  }

  @Post('/template')
  async templateScreen(@Body() data: any) {
    const res = await (this.service as any).templateScreen(data);
    return res ? this.ok(res) : this.fail();
  }
}
